package server2;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.sql.SQLException;

import database.Base;

public class Process implements Runnable {
	private Socket socketL, socketR;
	private BufferedReader readerL, readerR;
	private BufferedWriter writerL, writerR;
	private int portR;
	private int mainPort;
	private boolean isSent;
	public int lamport;

	public Process(Socket socket, int portR) {
		this.socketL = socket;
		this.portR = portR;
		
		try {
			readerL = new BufferedReader(new InputStreamReader(
					this.socketL.getInputStream()));
			writerL = new BufferedWriter(new OutputStreamWriter(
					this.socketL.getOutputStream()));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void writeL(String message) {
		try {
			writerL.write(message);
			writerL.newLine();
			writerL.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public String readL() {
		try {
			return readerL.readLine();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			return "";
		}
	}

	public void writeR(String message) {
		try {
			writerR.write(message);
			writerR.newLine();
			writerR.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public String readR() {
		try {
			return readerR.readLine();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			return "";
		}
	}

	public void run() {
		// TODO Auto-generated method stub
		String inStr, outStr;
		String[] inStrE;
		
		while (true) {
			this.isSent = true;

			inStr = this.readL();
			inStrE = inStr.split("[?]");

			inStrE[0] = initializeSend(inStrE[0]);

			String[] inStrE2 = inStrE[1].split("[&]");
			this.mainPort = Integer.parseInt(inStrE2[1]);
			this.lamport = Integer.parseInt(inStrE2[2]);
			inStrE[1] = inStrE2[0];

			display(inStrE[0] + "?" + inStrE[1]);

			if (this.mainPort == 2013) {

				outStr = updateLast(inStrE[0], inStrE[1]);

				this.writeL(outStr);

				inStr = this.readL();
				inStrE = inStr.split("[?]");

				display(inStr);

				outStr = updateLast(inStrE[0], inStrE[1]);

				String[] dataStrE = inStrE[1].split("[|]");
				this.insertData(Server.ISERVER, dataStrE[0],
						Integer.parseInt(dataStrE[1]), dataStrE[2]);

				this.writeL(outStr);

			} else {
				try {
					this.socketR = new Socket("localhost", this.portR);

					readerR = new BufferedReader(new InputStreamReader(
							this.socketR.getInputStream()));
					writerR = new BufferedWriter(new OutputStreamWriter(
							this.socketR.getOutputStream()));

					outStr = updateFirstAndMiddle(inStrE[0], inStrE[1]);

					this.writeR(outStr);

					this.isSent = false;

					inStr = this.readR();
					inStrE = inStr.split("[?]");

					display(inStr);

					outStr = updateFirstAndMiddle(inStrE[0], inStrE[1]);

					this.writeL(outStr);

					// UPDATED
					inStr = this.readL();
					inStrE = inStr.split("[?]");

					inStrE[0] = initializeUpdate(inStrE[0]);

					display(inStrE[0] + "?" + inStrE[1]);

					outStr = updateFirstAndMiddle(inStrE[0], inStrE[1]);

					this.writeR(outStr);

					inStr = this.readR();
					inStrE = inStr.split("[?]");

					display(inStr);

					outStr = updateFirstAndMiddle(inStrE[0], inStrE[1]);

					this.writeL(outStr);

				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

	private void insertData(int iServer, String pProductName, int pQuantity,
			String pDesTime) {
		Base base = new Base();
		base.open();

		try {
			base.getCon()
					.createStatement()
					.executeUpdate(
							"insert into Register" + iServer + " values('"
									+ pProductName + "', " + pQuantity + ", '"
									+ pDesTime + "')");
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		base.close();
	}

	private String initializeUpdate(String inStrE) {
		// TODO Auto-generated method stub
		if (inStrE.indexOf("Client") >= 0) {
			int iServer = inStrE.charAt(7) - 48;
			iServer = iServer == 5 ? 1 : iServer + 1;

			return "0|11111|" + this.lamport + "|" + "Server " + iServer
					+ "|Updated|3|123";
		}

		return inStrE;
	}

	private String updateLast(String inStrE, String dataStr) {
		// TODO Auto-generated method stub
		String[] inStrE2 = inStrE.split("[|]");
		int start = Integer.parseInt(inStrE2[0]);
		String jeton = inStrE2[1];
		String type = inStrE2[4];
		int action = Integer.parseInt(inStrE2[5]);
		String circle = inStrE2[6];

		start = 1;

		if (jeton.indexOf("0") >= 0) {
			jeton = jeton.replaceFirst("0", "1");
		}

		if (start == 1 && action == 1) {
			type = "Temped";
		} else if (start == 1 && action == 3) {
			type = "Synchronized";
		}

		action++;

		return start + "|" + jeton + "|" + this.lamport + "|"
				+ Server.SERVER_NAME + "|" + type + "|" + action + "|" + circle
				+ "?" + dataStr;
	}

	private String updateFirstAndMiddle(String inStrE, String dataStr) {
		// TODO Auto-generated method stub
		String[] inStrE2 = inStrE.split("[|]");
		int start = Integer.parseInt(inStrE2[0]);
		String jeton = inStrE2[1];
		String type = inStrE2[4];
		int action = Integer.parseInt(inStrE2[5]);
		String circle = inStrE2[6];

		start++;

		if (jeton.indexOf("0") >= 0) {
			jeton = jeton.replaceFirst("0", "1");
		}

		if ("Send".equals(type)) {
			type = "Locked";
		}

		if (start == 5 && action == 2) {
			start = 1;
			type = "Updated";
			action++;
		}

		if ("Synchronized".equals(type)) {
			String[] dataStrE = dataStr.split("[|]");
			this.insertData(Server.ISERVER, dataStrE[0],
					Integer.parseInt(dataStrE[1]), dataStrE[2]);
		}

		if (this.isSent) {
			return start + "|" + jeton + "|" + this.lamport + "|"
					+ Server.SERVER_NAME + "|" + type + "|" + action + "|"
					+ circle + "?" + dataStr + "&" + this.mainPort + "&" + this.lamport;
		} else {
			return start + "|" + jeton + "|" + this.lamport + "|"
					+ Server.SERVER_NAME + "|" + type + "|" + action + "|"
					+ circle + "?" + dataStr;
		}
	}

	private void display(String inStr) {
		// TODO Auto-generated method stub
		String[] inStrE = inStr.split("[?]");
		String[] inStrE2 = inStrE[0].split("[|]");
		int start = Integer.parseInt(inStrE2[0]);
		String jeton = inStrE2[1];
		String servername = inStrE2[3];
		String type = inStrE2[4];
		int action = Integer.parseInt(inStrE2[5]);
		String circle = inStrE2[6];

		if (start != 0 || !type.equals("Updated")) {
			String oldInfo = Server.infoJTA.getText() + "\n" + "->\n";
			oldInfo += "Start: " + start + "\n";
			oldInfo += "Jeton: " + jeton + "\n";
			oldInfo += "Lamport: " + this.lamport + "\n";
			oldInfo += "From: " + servername + "\n";
			oldInfo += "Type: " + type + "\n";
			oldInfo += "Action: " + action + "\n";
			oldInfo += "Vongdk: " + circle + "\n";
			Server.infoJTA.setText(oldInfo);
		}
	}

	private String initializeSend(String inStrE) {
		// TODO Auto-generated method stub

		if (inStrE.indexOf("Client") >= 0) {
			return "0|00000|" + this.lamport + "|Client|Send|1|123";
		}

		return inStrE;
	}
}
